

/**
 * @brief 二维向量或数组
 *      没有提供范围检查，但可以通过加入 assert进行判断
 *      定义NDEBUG就可以把assert 的影响消掉。排错很有用。
 *      只有fortran 风格的取值方式
 * 
 * @file vec2d.h
 * @author your name
 * @date 2018-08-13
 */
#ifndef VEC2D_H
#define VEC2D_H
#include <cassert>
#include <cstring>
template <typename T>
struct vec2d
{
    using iter = T *;
    using const_iter = const T *;
    using value_type = T;

    vec2d() noexcept = default;
    vec2d(size_t i, size_t j) noexcept
        : d1{i}, d2{j}, elem{new T[i * j]} {}
    vec2d(const vec2d &) noexcept;
    vec2d(vec2d &&) noexcept;
    ~vec2d() { delete[] elem; }

    inline vec2d &operator=(const vec2d &) noexcept;
    inline vec2d &operator=(vec2d &&) noexcept;
    template <typename C>
    inline vec2d &operator=(const C &) noexcept;

    T &operator()(size_t i, size_t j) noexcept
    {
        assert(i * d2 + j < d1 * d2);
        return elem[i * d2 + j];
    }
    const T &operator()(size_t i, size_t j) const noexcept
    {
        assert(i * d2 + j < d1 * d2);
        return elem[i * d2 + j];
    }

    // 好像没啥意义
    iter begin() noexcept { return elem; }
    const_iter begin() const noexcept { return elem; }
    iter end() noexcept { return elem + d1 * d2; }
    const_iter end() const noexcept { return elem + d1 * d2; }

    size_t size() const noexcept { return d1 * d2; }
    size_t dim1() const noexcept { return d1; }
    size_t dim2() const noexcept { return d2; }

    inline void reshape(size_t i, size_t j) noexcept;
    inline void copyFrom(const vec2d &src) noexcept;
    template <typename C>
    vec2d &operator*=(const C factor) noexcept;

  private:
    T *elem = nullptr;
    size_t d1{0}, d2{0};

    inline void copy_from(const vec2d &);
    inline void move_from(vec2d &); //引用的引用 没问题
};

template <typename T>
void vec2d<T>::copy_from(const vec2d &src)
{
    d1 = src.d1;
    d2 = src.d2;
    elem = new T[d1 * d2];
    memcpy(elem, src.elem, sizeof(T) * d1 * d2);
}

template <typename T>
void vec2d<T>::move_from(vec2d &src)
{
    d1 = src.d1;
    d2 = src.d2;
    elem = src.elem;
    src.elem = nullptr;
    src.d1 = src.d2 = 0;
}

template <typename T>
vec2d<T>::vec2d(const vec2d &src) noexcept
{
    copy_from(src);
}

template <typename T>
vec2d<T> &vec2d<T>::operator=(const vec2d &src) noexcept
{
    if (this == &src)
        return *this;
    if (elem)
        delete [] elem;
    copy_from(src);
    return *this;
}
// 只有两者维度相同才能赋值, 否则没有物理意义
// template <typename T>
// vec2d<T> &vec2d<T>::operator=(const vec2d &src) noexcept
// {
//     if (this == &src)
//         return *this;
//     assert((d1 == src.d1) && (d2 == src.d2));
//     memcpy(elem, src.elem, sizeof(T) * d1 * d2);
//     return *this;
// }

template <typename T>
vec2d<T>::vec2d(vec2d &&src) noexcept
{
    move_from(src);
}

template <typename T>
vec2d<T> &vec2d<T>::operator=(vec2d &&src) noexcept
{
    // 也要防止自赋值的发生
    if (this == &src)
        return *this;
    if (elem)
        delete [] elem;
    move_from(src);
}
// 只有两者维度相同才能赋值, 否则没有物理意义
// template <typename T>
// vec2d<T> &vec2d<T>::operator=(vec2d &&src) noexcept
// {
//     if (this == &src)
//         return *this;
//     assert((d1 == src.d1) && (d2 == src.d2));
//     elem = src.elem;
// }

template <typename T>
template <typename C>
vec2d<T> &vec2d<T>::operator=(const C &a) noexcept
{
    size_t size = d1 * d2;
    for (size_t i = 0; i < size; ++i)
        elem[i] = a;
    return *this;
}

template <typename T>
void vec2d<T>::reshape(size_t i, size_t j) noexcept
{
    delete[] elem;
    elem = new T[i * j];
    d1 = i;
    d2 = j;
}

template <typename T>
void vec2d<T>::copyFrom(const vec2d &src) noexcept
{
    assert((d1 == src.d1) && (d2 == src.d2));
    memcpy(elem, src.elem, sizeof(T) * d1 * d2);
}

template <typename T>
template <typename C>
vec2d<T> &vec2d<T>::operator*=(const C factor) noexcept
{
    size_t size = d1 * d2;
    for (size_t i = 0; i < size; ++i)
        elem[i] *= factor;

    return *this;
}

#endif